#include <string>
#include <map>
#include <vector>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"

// 需要ip和端口 期间套接字的返回值是一个fd文件描述符
class Udp_Server
{
public:
    Udp_Server(uint16_t port, const std::string ip = "") : _ip(ip), _port(port), _socket(-1)
    {
    }

    bool init()
    {
        // 需要创建套接字socket和bind
        _socket = socket(AF_INET, SOCK_DGRAM, 0);
        if (_socket < 0)
        {
            Messagelog(FATAL, "%s:%d-%s", "socket", errno, strerror(errno));
            exit(2);
        }

        // 绑定套接字的ip和port，要保持网络大端的要求
        struct sockaddr_in sockaddr;
        memset(&sockaddr, 0, sizeof sockaddr);
        sockaddr.sin_port = htons(_port);
        // sockaddr.sin_addr.s_addr = inet_addr(_ip.c_str());
        sockaddr.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        sockaddr.sin_family = AF_INET;

        if (bind(_socket, (struct sockaddr *)&(sockaddr), sizeof(sockaddr)) < 0)
        {
            Messagelog(FATAL, "%s:%d-%s", "bind", errno, strerror(errno));
            exit(3);
        }
        // 成功
        Messagelog(NORMAL, "init udp server done ... %s", strerror(errno));
        return true;
    }

    void start()
    {
        // echo server:接收client发来的消息，cout 客户端的ip和prot+mesg
        char buffer[1024];
        char key[256];

        while (true)
        {
            struct sockaddr_in peer;
            memset(&peer, 0, sizeof peer);
            socklen_t len = sizeof peer;

            ssize_t sz = recvfrom(_socket, buffer, sizeof buffer - 1, 0, (struct sockaddr *)&peer, &len);
            Messagelog(DEBUG, "%s", "接收到一条client的信息");
            buffer[sz] = 0;
            // 处理数据的方式
            // 3. 聊天室
            // std::string key;
            // key += inet_ntoa(peer.sin_addr);
            // key += peer.sin_port
            if (sz > 0)
            {
                char *client_ip = inet_ntoa(peer.sin_addr);
                uint16_t client_port = ntohs(peer.sin_port);
                int size = sprintf(key, "[%s-%u]", client_ip, client_port);
                key[size] = '\0';
                if (_user.find(key) == _user.end())
                {
                    _user.insert({key, peer});
                    Messagelog(NORMAL, "添加一个用户：%s", key);
                    sendto(_socket, _old.c_str(), _old.size(), 0, (struct sockaddr*)&peer, sizeof(peer));// 历史消息推送
                }
                std::string ret_message(key);
                ret_message += buffer;
                // for (auto &iter : _user)
                // {
                //     Messagelog(NORMAL, "push message to %s", iter.first.c_str());
                //     // 可以xiugai
                //     sendto(_socket, ret_message.c_str(), ret_message.size(), 0, (struct sockaddr*)&iter.second, sizeof(iter.second));
                // }
                _old += (ret_message + "\n");
                std::vector<std::string> del;
                for (auto &iter : _user)
                {
                    Messagelog(NORMAL, "push message to %s", iter.first.c_str());
                    // 可以xiugai
                    ssize_t sz = sendto(_socket, ret_message.c_str(), ret_message.size(), 0, (struct sockaddr*)&iter.second, sizeof(iter.second));
                    std::cout << "成功发送" << iter.first << std::endl;
                    if(sz < 0)
                    {
                        del.push_back(iter.first);
                    }
                }
                for(auto& it : del)
                {
                    _user.erase(it);
                    std::cout << "删除用户：" << it  << std::endl;
                }
            }

            // 2. 执行命令
            // char result[256];
            // std::string command = buffer;
            // FILE* fp = popen(buffer, "r");// popen会创建子进程，执行命令，并返回结果到文件fp
            // if(fp == nullptr) // 这里为空表示：创建子进程失败，fork或者pipe失败
            // {
            //     Messagelog(ERROR, "popen(%s):%d-%s", buffer, errno, strerror(errno));
            //     sendto(_socket, command.c_str(), command.size(), 0, (struct sockaddr*)&peer, len);
            //     continue;
            // }
            // else
            // {
            //     int count = 0;
            //     while(fgets(result, sizeof result, fp) != nullptr && ++count)
            //         command += result;
            //     if(!count)
            //         command += " command not find";
            //     sendto(_socket, command.c_str(), command.size(), 0, (struct sockaddr*)&peer, len);
            // }
            // fclose(fp);

            // 1. echo
            // if(sz > 0)
            // {
            //     char* client_ip = inet_ntoa(peer.sin_addr);
            //     uint16_t client_port = ntohs(peer.sin_port);

            //     printf("[%s-%u]:%s\n", client_ip, client_port, buffer);
            // }
            // 分析数据
            // 写回数据
            // sendto(_socket, buffer, strlen(buffer), 0, (struct sockaddr*)&peer, len);
        }
    }

    ~Udp_Server()
    {
        if (_socket > 0)
            close(_socket);
    }

private:
    std::string _ip;
    uint16_t _port;
    int _socket;

    std::string _old = "历史消息：\n";
    std::map<std::string, struct sockaddr_in> _user;
};